window.SVGMap = (function () {
	var SM = function (){
			return SM.init.apply(SM, arguments);
    	},
		undefined,
		doc = document,
		win = window,
		svgns = 'http://www.w3.org/2000/svg';

	// Partially borrowed from RaphaelJS lib by D. Baranosvkiy.
    SM.type = (window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML");

	SM.getContainer = function (container) {
		if (typeof container == "string")
			container = doc.getElementById(container);

		if (container.tagName) {
			this.container = container;

			if (this.options.width == undefined)
				this.options.width = container.style.pixelWidth || container.offsetWidth;
				
			if (this.options.height == undefined)
				this.options.height = container.style.pixelHeight || container.offsetHeight;
		} else 
			throw "No container available";
	};
	
	var extend = function(destination, source) {
					for (var property in source)
						destination[property] = source[property];
					return destination;
				},
		cloneArray = function(source){
					return source.slice(0, source.length);
				},
		formatCoord = function(num) {
					return	SM.type == 'SVG'
							? num.toFixed(3)
							: Math.round(num) - 1;
				},
		isFunction = function(obj) {
					return typeof obj === "function";
				},
		whateverHandler = function(id, baseOptions, callback) {
					if (isFunction(callback)) {
						options = callback(id);
						if (options === false)
							return false;
							
						return (options === true || options == undefined)
									? baseOptions
									: extend(extend({}, baseOptions), options);
					} else
						return baseOptions;
				
				},
		mouseoverHandler = function(event) {
					var options = whateverHandler(this.region, SM.options.hover, SM.options.onHover);
					if (options) {
						setAttrs(this, options);
						this.parentNode.appendChild(this);
					};
				},
		drawHandler = function(event) {
					var options = whateverHandler(this.region, SM.options.normal, SM.options.onShow);
					options && setAttrs(this, options);
				},
		clickHandler = function(event) {
					var options = whateverHandler(this.region, SM.options.hover, SM.options.onClick);
					options && setAttrs(this, options);
				};

	if (SM.type == 'SVG') {
		function renderPath(id, data) {
			var path = '', i, j, len = data.length, el, reg_length;
			if (len == 0)
				return false;

			for (i = 0; i < len; i++) {
				for (j = 0, reg_length = data[i].length; j < reg_length; j++)
					path += (j == 0 ? 'm' : 'l') + formatCoord(data[i][j][0]) + ',' + formatCoord(data[i][j][1])  + ' ';
				
				path += 'z';
			}
			
			
			el = doc.createElementNS(svgns, "path");
			this.canvas.appendChild(el);
			el.setAttribute('d', path);
			
			el.region = id;
			
			return el;
		};
		
		function setAttrs(el, options) {
			options.stroke != undefined && el.setAttribute('stroke', options.stroke);
			options.fill != undefined && el.setAttribute('style', 'fill:' + options.fill);
			options['stroke-width'] != undefined && el.setAttribute('stroke-width', options['stroke-width']);
		};
		
		function attachEvent(element, event, observer) {
			var f = function (e) {
				return observer.call(element, e);
			};
			element.addEventListener(event, f, false);
		}

		// SVG code
		SM.init = function(container, data, options) {
			var self = this, i;
			
			this.options = extend({
					normal: {
						'stroke': '#FF9D40',
						'fill': '#FFB773',
						'stroke-width': 1
					},
					hover: {
						'stroke': '#FF7C00',
						'fill': '#04859D',
						'stroke-width': 1
					},
					zoom: -1
				},
				options || {});
			this.getContainer(container);

			this.canvas = doc.createElementNS(svgns, "svg");
			this.canvas.setAttribute("width", this.options.width);
			this.canvas.setAttribute("height", this.options.height);

			if (this.container.firstChild)
				this.container.insertBefore(this.canvas, this.container.firstChild);
			else
				this.container.appendChild(this.canvas);

			this.options.zoom = this.options.zoom != -1
								? this.options.zoom
								: Math.min(this.options.width / data.meta.width, this.options.height / data.meta.height);
			
			for (i in data.map)
				this.addRegion(i, data.map[i]);
		};
			
		SM.addRegion = function(id, coords) {
			var data = cloneArray(coords),
				i, j, len = data.length, options, path, reg_length;
			
			for (i = 0; i < len; i++) 
				for (j = 0, reg_length = data[i].length; j < reg_length; j++) {
					data[i][j][0] *= this.options.zoom / 100;
					data[i][j][1] *= this.options.zoom / 100;
				}
			
			options = whateverHandler(id, this.options.normal, this.options.onShow);
			if (!options)
				return;

			path = renderPath.call(this, id, data);
			setAttrs(path, options);
			attachEvent(path, 'mouseover', mouseoverHandler);
			attachEvent(path, 'mouseout', drawHandler);
			attachEvent(path, 'click', clickHandler);
		};
		
	} else {
	// VML code
		
	}
	
    return SM;
})();